package base;

import device.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import messages.DevMessage;

import java.io.IOException;
import java.nio.channels.SocketChannel;
import java.util.Collection;
import java.util.HashMap;

public class DeviceBase {
    private final UsersBaseInterface usersBase;
    private final HashMap<SocketChannel, Device> deviceFilterBySocket;
    private final HashMap<String, SocketChannel> socketFilterByID;
    private final HashMap<String, Device> deviceFilterByID;
    private static final Logger logger = LoggerFactory.getLogger(DeviceBase.class);

    public DeviceBase(UsersBaseInterface usersBase) {
        this.usersBase = usersBase;
        deviceFilterBySocket = new HashMap<>();
        socketFilterByID = new HashMap<>();
        deviceFilterByID = new HashMap<>();
    }

    public Device getDeviceByID(String deviceID) {
        return deviceFilterByID.get(deviceID);
    }

    public void removeDevice(SocketChannel deviceChannel) throws IOException {
        Device dev = deviceFilterBySocket.get(deviceChannel);
        if (dev == null) {
            return;
        }
        Collection<Device> devices = deviceFilterByID.values();
        for (Device targetDev : devices) {
            if (!dev.equals(targetDev)) {
                dev.unSubscribe(targetDev);
            }
        }
        logger.info("关闭连接 [{}] 并移除设备 [{}]", deviceChannel.getLocalAddress(), dev.getDeviceID());
        socketFilterByID.remove(dev.getDeviceID());
        deviceFilterByID.remove(dev.getDeviceID());
        deviceFilterBySocket.remove(deviceChannel);
    }

    // 注册设备，注册成功返回 0，失败返回 1
    public int registerDevice(SocketChannel deviceChannel, DevMessage devMessage) {
        Device dev = switch (devMessage.getDeviceType()) {
            case DEVICE_TYPE_EMBEDDED -> new Embedded(deviceChannel, usersBase);
            case DEVICE_TYPE_TERMINAL -> new Terminal(deviceChannel, usersBase);
            case DEVICE_TYPE_ADMIN -> new AdminDevice(deviceChannel, usersBase);
            case DEVICE_TYPE_MEDICINE_BOX -> new MedicineBox(deviceChannel, usersBase);
            case DEVICE_TYPE_MY_PHONE -> new MyPhone(deviceChannel, usersBase);
            default -> null;
        };
        if (dev == null) {
            logger.warn("注册设备失败，设备类型有误 [{}]", devMessage.getMessageType());
            return 1;
        }

        /* 若找到相同 deviceID 的设备，则先关闭原有设备，再注册新设备 */
        SocketChannel oldChannel = socketFilterByID.get(devMessage.getDeviceID());
        if (oldChannel != null) {
            try {
                removeDevice(oldChannel);
                logger.info("移除旧的设备 [{}]", devMessage.getDeviceID());
            } catch (IOException e) {
                logger.error("移除旧设备时出错：{}", e.toString());
            }
        }

        dev.setDeviceID(devMessage.getDeviceID());
        HashMap<String, String> dict = devMessage.getMsgDict();
        //Collection<String> collection = messages.getMsgDictKeys();
        dev.registerKeysDict(dict);
        deviceFilterBySocket.put(deviceChannel, dev);
        socketFilterByID.put(dev.getDeviceID(), deviceChannel);
        deviceFilterByID.put(dev.getDeviceID(), dev);
        dev.afterRegisterCall();
        return 0;
    }
}
